import { Platform } from 'react-native';
import DeviceInfo from 'react-native-device-info';

import axios, { AxiosRequestConfig } from 'axios';

import {
  ACCESS_TOKEN,
  ACCESS_TOKEN_EXPIRE_TIME,
  APP_NAME,
  DEVICE_ID,
  REFRESH_TOKEN,
  REFRESH_TOKEN_EXPIRE_TIME,
  USER_ID,
} from '../constants';
import { getStorageItem, getStorageNumberItem } from './storage';
import { setUserLoginToken } from '@/api';
import { userAPI } from '@/api/userAPI';

// 注意：切换接口地址时，不要忘了切换websocket地址
// 测试环境接口地址,baseURL+xx
export const baseURLMiddle = 'tsapiv1-test.shasoapp.com';
// 生产环境接口地址,baseURL+xx
// export const baseURLMiddle = 'tsapiv1.shasoapp.com';
export const baseURL = `https://${baseURLMiddle}`;

// 是否是测试环境
export const isShowTestURL = baseURL.includes('test');

// HTTP 请求实例
export const http = axios.create({
  baseURL: baseURL,
  // 现在只使用英文lang
  headers: {
    'Content-Type': 'application/json',
    // "lang": LANG_MAP[language] || 'en_US',
    // lang: 'zh_CN',
    'ts-app-version': DeviceInfo.getVersion(),
    'ts-app-platform': Platform.OS,
    'ts-app-name': APP_NAME,
    'ts-request-id': new Date().getTime().toString(),
    lang: 'en_US',
  },
  // 超时时间，10秒
  timeout: 20 * 1000,
});

// 错误处理;
const handleError: Parameters<typeof http.interceptors.response.use>[1] = async (error) => {
  console.log('http handleError===', error);
  if (error.response?.status && error.response.status === 401) {
    console.log('401===');
    // 如果是未授权错误，可能是 accessToken 过期了，先尝试使用 refreshToken 刷新 accessToken
    const refreshToken = getStorageItem(REFRESH_TOKEN);
    const refreshTokenExpireTime = getStorageNumberItem(REFRESH_TOKEN_EXPIRE_TIME);

    // 如果 refreshToken 未过期，则使用refreshToken获取新的accessToken
    if (refreshToken && refreshTokenExpireTime && refreshTokenExpireTime > Date.now()) {
      try {
        // 刷新accessToken
        const res = await userAPI.auth_login({
          grantType: 'refreshToken',
          appName: APP_NAME,
          refreshToken: refreshToken,
          userType: 'app_user',
        });

        // 本地存储用户信息
        setUserLoginToken(res.data);

        // 更新 accessToken
        error.config.headers.Authorization = `Bearer ${res.data.accessToken}`;
        // 重新发起请求
        return axios.request(error.config);
      } catch (err) {
        console.error('refresh token error:', err);
        return;
      }
    } else {
      // 如果refreshToken已过期，则重新发起设备号登录请求,更新accessToken和refreshToken
      const deviceId = getStorageItem(DEVICE_ID);
      console.log('====================================');
      console.log('deviceId:', deviceId);
      console.log('====================================');
      if (deviceId) {
        const res = await userAPI.device_login({
          appName: APP_NAME,
          deviceId: deviceId,
        });
        // 本地存储用户信息
        setUserLoginToken(res.data);
        // 更新 accessToken
        error.config.headers.Authorization = `Bearer ${res.data.accessToken}`;
        // 重新发起请求
        return axios.request(error.config);
      }
      return;
    }
  }
  return Promise.reject(error);
};
// 所有请求中断

// 请求拦截器
http.interceptors.request.use(async (config) => {
  // 在发送请求之前，判断accessToken情况
  // 注意是number类型
  // 用户accessToken过期时间
  const accessTokenExpireTime = getStorageNumberItem(ACCESS_TOKEN_EXPIRE_TIME);
  // 当前时间
  const currentTime = Date.now();

  // 如果 accessToken 已过期
  if (accessTokenExpireTime && accessTokenExpireTime < currentTime) {
    // 当前refreshToken
    const refreshToken = getStorageItem(REFRESH_TOKEN);
    // 当前refreshToken 过期时间
    const refreshTokenExpireTime = getStorageNumberItem(REFRESH_TOKEN_EXPIRE_TIME);

    try {
      // 如果 refreshToken 未过期，则使用refreshToken获取新的accessToken
      if (refreshToken && refreshTokenExpireTime && refreshTokenExpireTime > Date.now()) {
        const res = await userAPI.auth_login({
          grantType: 'refreshToken',
          appName: APP_NAME,
          refreshToken: refreshToken,
          userType: 'app_user',
        });

        // 本地存储用户信息
        setUserLoginToken(res.data);

        // 更新accessToken
        config.headers.Authorization = `Bearer ${res.data.accessToken}`;
        // 发起请求
        return config;
      } else {
        // 如果refreshToken已过期,说明需要重新发起登录请求登录
        const deviceId = getStorageItem(DEVICE_ID);
        if (deviceId) {
          const res = await userAPI.device_login({
            appName: APP_NAME,
            deviceId: deviceId,
          });
          // 本地存储用户信息
          setUserLoginToken(res.data);
          // 更新accessToken
          config.headers.Authorization = `Bearer ${res.data.accessToken}`;
        }
        // 发起请求
        return config;
      }
    } catch (error) {
      console.error('refresh token error:', error);
      // 放行config继续请求，让后端返回401,触发handleError
      return config;
    }
  }

  // 如果accessToken存在并且没有过期，则设置请求头
  if (getStorageItem(ACCESS_TOKEN)) {
    // 设置请求头
    config.headers.Authorization = `Bearer ${getStorageItem(ACCESS_TOKEN)}`;
    config.headers['ts-user-id'] = getStorageItem(USER_ID);
  }
  return config;
}, handleError);

// 响应拦截器
http.interceptors.response.use(async (response) => {
  const data = response.data;
  // 请求状态码为200
  if (response?.status && response.status === 200) {
    // 并且业务code为0（正常)
    if (data.code === 0) {
      return response;
    }

    // 如果业务异常码为44100,短信验证码过期
    if (data.code === 44100) {
      return Promise.reject(response);
    }

    // 如果业务异常码为44900，refresh token无效
    if (data.code === 44900) {
      console.error('44900 error', data);
      // 重新请求一次设备号登录,更新accessToken和refreshToken
      const deviceId = getStorageItem(DEVICE_ID);
      if (deviceId) {
        console.log('44900 device_login ====');
        const res = await userAPI.device_login({
          appName: APP_NAME,
          deviceId: deviceId,
        });
        // 本地存储用户信息
        setUserLoginToken(res.data);
      }
      return Promise.reject(response);
    }
    // 业务 code不为0，也正常返回，code的异常给业务代码处理，因为调用第三方接口就不会code=0
    return response;
  }
  return Promise.reject(response);
}, handleError);

// get请求
export const get = <T>(
  url: string,
  params?: API.Param,
  headers?: Record<string, string | number | boolean | undefined>,
  config?: AxiosRequestConfig,
) => {
  return http<T>({
    method: 'get',
    url,
    params,
    headers,
    paramsSerializer: { indexes: null },
    ...config,
  });
};
// post请求
export const post = <T>(url: string, data?: API.Param, config?: AxiosRequestConfig) => {
  return http<T>({
    method: 'post',
    url,
    data,
    ...config,
  });
};
// put请求
export const put = <T>(url: string, data?: API.Param, config?: AxiosRequestConfig) => {
  return http<T>({
    method: 'put',
    url,
    data,
    ...config,
  });
};
// delete请求
export const del = <T>(url: string, data?: API.Param, config?: AxiosRequestConfig) => {
  return http<T>({
    method: 'delete',
    url,
    data,
    ...config,
  });
};
